package com.note.app.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.note.app.document.NoteContent;
import com.note.app.dto.NoteDTO;
import com.note.app.dto.ShareCreateDTO;
import com.note.app.dto.ShareDTO;
import com.note.app.dto.TagDTO;
import com.note.app.mapper.NoteMapper;
import com.note.app.mapper.ShareMapper;
import com.note.app.mapper.UserMapper;
import com.note.app.repository.NoteContentRepository;
import com.note.app.service.NoteService;
import com.note.app.service.ShareService;
import com.note.app.service.TagService;
import com.note.common.domain.Note;
import com.note.common.domain.Share;
import com.note.common.domain.User;
import com.note.common.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 分享服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ShareServiceImpl implements ShareService {

    private final ShareMapper shareMapper;
    private final NoteMapper noteMapper;
    private final UserMapper userMapper;
    private final NoteService noteService;
    private final TagService tagService;
    private final NoteContentRepository noteContentRepository;

    @Value("${share.base-url:http://localhost:8080/share}")
    private String shareBaseUrl;

    @Value("${share.default-expire-days:7}")
    private int defaultExpireDays;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ShareDTO createShare(Long userId, ShareCreateDTO dto) {
        // 1. 检查笔记是否存在且用户有权限
        Note note = noteMapper.selectById(dto.getNoteId());
        if (note == null) {
            throw new BusinessException("笔记不存在");
        }

        if (!note.getUserId().equals(userId)) {
            throw new BusinessException("无权限分享该笔记");
        }

        // 2. 生成唯一令牌
        String token = generateUniqueToken();

        // 3. 创建分享
        Share share = new Share();
        share.setNoteId(dto.getNoteId());
        share.setUserId(userId);
        share.setToken(token);
        share.setPermission(dto.getPermission());
        share.setCreatedAt(LocalDateTime.now());
        share.setUpdatedAt(LocalDateTime.now());


        // 设置过期时间，如果未指定则使用默认
        if (dto.getExpiredAt() != null) {
            share.setExpiredAt(dto.getExpiredAt());
        } else {
            share.setExpiredAt(LocalDateTime.now().plusDays(defaultExpireDays));
        }

        // 4. 保存分享
        shareMapper.insert(share);

        // 5. 转换为DTO并返回
        ShareDTO shareDTO = convertToDTO(share);
        shareDTO.setShareLink(shareBaseUrl + "/" + token);
        shareDTO.setNoteTitle(note.getTitle());

        // 6. 获取用户信息
        enrichUserInfo(List.of(shareDTO));

        return shareDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelShare(Long userId, Long shareId) {
        // 1. 检查分享是否存在
        Share share = shareMapper.selectById(shareId);
        if (share == null) {
            throw new BusinessException("分享不存在");
        }

        // 2. 检查是否有权限取消（分享创建者或笔记拥有者）
        if (!share.getUserId().equals(userId)) {
            Note note = noteMapper.selectById(share.getNoteId());
            if (note == null || !note.getUserId().equals(userId)) {
                throw new BusinessException("无权限取消该分享");
            }
        }

        // 3. 逻辑删除分享
        return shareMapper.deleteById(shareId) > 0;
    }

    @Override
    public NoteDTO getNoteByShareToken(String token) {
        // 1. 查询分享信息
        Share share = shareMapper.selectByToken(token);
        if (share == null) {
            throw new BusinessException("分享不存在或已过期");
        }

        // 2. 直接获取笔记，不经过权限检查
        Note note = noteMapper.selectById(share.getNoteId());
        if (note == null) {
            throw new BusinessException("笔记不存在");
        }

        // 3. 转换为DTO
        NoteDTO noteDTO = new NoteDTO();
        BeanUtils.copyProperties(note, noteDTO);

        // 4. 获取笔记内容
        Optional<NoteContent> contentOpt = noteContentRepository.findByNoteIdAndVersion(note.getId(), note.getVersion());
        if (contentOpt.isPresent()) {
            noteDTO.setContent(contentOpt.get().getContent());
        }

        // 5. 获取标签列表
        List<TagDTO> tags = tagService.getTagsByNoteId(note.getId());
        noteDTO.setTags(tags);

        // 6. 增加笔记浏览次数
        noteService.incrementViewCount(share.getNoteId());

        return noteDTO;
    }

    @Override
    public Page<ShareDTO> getUserShares(Long userId, long current, long size) {
        // 1. 分页查询用户分享
        Page<Share> page = new Page<>(current, size);
        IPage<Share> sharePage = shareMapper.selectPageByUserId(page, userId);

        // 2. 转换为DTO
        Page<ShareDTO> result = new Page<>(sharePage.getCurrent(), sharePage.getSize(), sharePage.getTotal());
        List<ShareDTO> records = sharePage.getRecords().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        // 3. 查询并设置笔记标题和用户信息
        enrichNoteInfo(records);
        enrichUserInfo(records);

        result.setRecords(records);
        return result;
    }

    @Override
    public Page<ShareDTO> getNoteShares(Long userId, Long noteId, long current, long size) {
        // 1. 检查笔记是否存在且用户有权限
        Note note = noteMapper.selectNoteWithPermission(noteId, userId);
        if (note == null) {
            throw new BusinessException("笔记不存在或无权限查看");
        }

        // 2. 分页查询笔记分享
        Page<Share> page = new Page<>(current, size);
        IPage<Share> sharePage = shareMapper.selectPageByNoteId(page, noteId);

        // 3. 转换为DTO
        Page<ShareDTO> result = new Page<>(sharePage.getCurrent(), sharePage.getSize(), sharePage.getTotal());
        List<ShareDTO> records = sharePage.getRecords().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        // 4. 设置笔记标题、分享链接和用户信息
        enrichNoteInfo(records);
        enrichUserInfo(records);

        result.setRecords(records);
        return result;
    }

    @Override
    public ShareDTO checkSharePermission(String token, boolean requireWrite) {
        // 1. 查询分享信息
        Share share = shareMapper.selectByToken(token);
        if (share == null) {
            return null; // 分享不存在或已过期
        }

        // 2. 检查权限
        if (requireWrite && !"WRITE".equals(share.getPermission())) {
            return null; // 需要写权限但分享仅有读权限
        }

        // 3. 转换为DTO
        ShareDTO shareDTO = convertToDTO(share);

        // 4. 查询并设置笔记标题
        Note note = noteMapper.selectById(share.getNoteId());
        if (note != null) {
            shareDTO.setNoteTitle(note.getTitle());
            shareDTO.setShareLink(shareBaseUrl + "/" + token);
        }

        // 5. 获取用户信息
        enrichUserInfo(List.of(shareDTO));

        return shareDTO;
    }

    /**
     * 生成唯一分享令牌
     */
    private String generateUniqueToken() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }

    /**
     * 将Share实体转换为ShareDTO
     */
    private ShareDTO convertToDTO(Share share) {
        ShareDTO dto = new ShareDTO();
        BeanUtils.copyProperties(share, dto);
        dto.setShareLink(shareBaseUrl + "/" + share.getToken());
        return dto;
    }

    /**
     * 批量填充用户信息
     */
    private void enrichUserInfo(List<ShareDTO> shares) {
        // 收集所有用户ID
        List<Long> userIds = shares.stream()
                .map(ShareDTO::getUserId)
                .distinct()
                .collect(Collectors.toList());

        if (!userIds.isEmpty()) {
            // 批量查询用户信息
            List<User> users = userMapper.selectBatchIds(userIds);
            Map<Long, User> userMap = users.stream()
                    .collect(Collectors.toMap(User::getId, user -> user));

            // 填充用户信息
            shares.forEach(share -> {
                User user = userMap.get(share.getUserId());
                if (user != null) {
                    share.setUserName(user.getUsername());
                }
            });
        }
    }

    /**
     * 批量填充笔记信息
     */
    private void enrichNoteInfo(List<ShareDTO> shares) {
        // 收集所有笔记ID
        List<Long> noteIds = shares.stream()
                .map(ShareDTO::getNoteId)
                .distinct()
                .collect(Collectors.toList());

        if (!noteIds.isEmpty()) {
            // 批量查询笔记信息
            List<Note> notes = noteMapper.selectBatchIds(noteIds);
            Map<Long, Note> noteMap = notes.stream()
                    .collect(Collectors.toMap(Note::getId, note -> note));

            // 填充笔记信息
            shares.forEach(share -> {
                Note note = noteMap.get(share.getNoteId());
                if (note != null) {
                    share.setNoteTitle(note.getTitle());
                }
            });
        }
    }
} 